-module(read_graph).
-compile(export_all).


% graphnode record:
-record(graphnode_record, {name = none, 
						   neighbors = [], 
						   t_neighbors = [], 
						   status = init}).
							



start(Filename) -> 
	io:format("at start ~n",[]),
	NameServerId = spawn(?MODULE, nameserver, [dict:new()]), 
	% register(gns, NameServerId),	

	{ok, F} = file:open(Filename, [read]), 
	treat_file_lines(F, 0, NameServerId).
	 

treat_file_lines(File, LineNum, Nameserver) ->	
	case io:get_line(File, '') of 
	
		eof -> done; 
		Line -> 
			% debug:
			io:format("treating line: ~p ~n", [Line]),

			{ok, LineAtoms, _} = erl_scan:string(Line), 
			Neighbors = extract_neighbors(LineAtoms),
			Record = #graphnode_record{name = LineNum, neighbors = Neighbors},
				
			Pid = spawn(?MODULE, graph_node, [Record]), 
	
			
			register_name(Nameserver, LineNum, Pid), 

			treat_file_lines(File, LineNum + 1, Nameserver)
		end. 


register_name(NameServerPid, Key, Value) ->
	io:format("at register_name ~n"),
	NameServerPid ! {self(), register_node, Key, Value}. 		

% take tokens generated by erl_scan:string to a list of integers
extract_neighbors(Token) ->
	extract_neighbors_helper(Token, []). 

extract_neighbors_helper([], Res) -> Res;
extract_neighbors_helper([H|T], Res) -> 
	case H of 
		{integer, _, X} -> 
			extract_neighbors_helper(T, lists:append(Res, [X]));
		H -> error
	end. 



% Apparantly there is no need for this function in this version of the code.
% link_to_existing_nodes(Pid, Neighbors, Nameserver) -> 
	% contact nameserver with all neighbors. 
	% if neighbor exist, then nameserver returns {ok, Pid_of_Neigbhor}, 
	% otherwise, it returns {not_exist}. 
	% Pid sends message {link_me} to Pid_of_Neighbor. 
	% at node()


nameserver(NodeDict) -> 
	receive 
		{_, register_node, Name, PID} ->
									io:format("received register_node ~n"), 
									NewNodeDict = dict:store(Name, PID, NodeDict),
									io:format("new ns dict: ~p ~n", dict:to_list(NewNodeDict)),
									nameserver(NewNodeDict);
		{From, get_pid, Name} -> 
								case dict:find(Name, NodeDict) of 
									{ok, Value} -> From ! Value; 
									error -> From ! not_found
								end;
		_ -> error   
	end. 


graph_node(Record) -> 
	io:format("at graph_node with id: ~p and Neighbors: ~p ~n", [Record#graphnode_record.name, Record#graphnode_record.neighbors]),
	receive 
		{From, execute_2hop} -> TwoNeighbors = execute_2hop(Record#graphnode_record.neighbors, []); 

		{From, Msg} -> From ! Msg
	end. 



% pseudocode: 
% 1. All nodes starts at the same time, this is a guaranteed by a central server 
% and a wake-up message.
% 2. At each node, send a message to {ex_neighbor} to each neighbor in a list Nv. 
% 	 A node deletes a neigbor from Nv once a message is either sent or received from it. 

% initial design (2-hop exchanger). 
% idea 1: At wake_up message -> graphnode goes to function executes algorithm. 
% 		  The parameters of the fucntion is Neighbors, and the output is 2-hop neighbors.
% 		  the main issue in this solution is that we can't keep track of other messages 
% 		  received at graphnode. --> in this case: we can answer to every not-wanted
%		  message by a 'busy' message. 
% idea 2: add a temporary varialbe to record 'graphnode_record' which holds information 
%		  needed by the new function [in our case, Nv]	-- this adds a a lot of extra 
%		  input parameters to function 'graphnode()'. 
% idea 3: create a spawn process: with input parameters Nv. - the question herein is 	
% 		  how to do iterations in function 'graphnode()' - without making modifications to 
%		  to receive clause. We may play with the status of graphnode and add a case of clause 
%		  before the receive clause.. however, this means that we wont accept the reception
%		  of any message ! and they all be stored in a queue. Because every node would send 
%		  but cannot receive, then we will end up in a deadlock. 
%		  Here comes the strength of synchronization: because we can synchrnoize, we can 
%		  divided our clock into send/receive status ! -- wow ! sometimes i love these silly things I discover ! :) 
% idea 4: [I dont know- I should think about it ! ]
% TODO: we will add synchroniazation to the nodegraph for now. 
% TODO: for now, we will consider idea 1.


% how do we receive messages in erlang - they are stored in 
% a queue. Each call of receive fetch a message. 
% so how do we do it ? 

